package tripx.site;

import java.util.ArrayList;
import java.util.HashMap;

import tripx.blog.Score;
import tripx.food.FoodPO;
import tripx.update.City;
import tripx.update.Food;
import tripx.update.Site;
import tripx.util.JsonHelper;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

/**
 * The wrapper for the SiteService, since the SiteService provides more standard
 * interfaces, we need to translate the raw request for the execution
 * 
 * @author zhb
 * 
 */
public class SiteServiceWrapper {

	// the target service to be wrappered
	private SiteService service;

	public SiteServiceWrapper() {
		service = new SiteService();
	}

	/**
	 * get site list by site name. consider there may exist some sites which
	 * owns the same name
	 * 
	 * @param siteName
	 * @return
	 */
	public String searchSiteBySiteName(String siteName) {
		String result = service.query("getSiteByName", siteName);

		Gson gson = new Gson();
		JsonParser parser = new JsonParser();
		JsonArray array = parser.parse(result).getAsJsonArray();

		ArrayList<SitePO> sitePOList = new ArrayList<SitePO>();
		for (JsonElement ele : array) {
			DbSite site = gson.fromJson(ele, DbSite.class);
			String cityName = service.queryString("getCityNameById", site.cid
					+ "");
			sitePOList.add(new SitePO(siteName, cityName, site.intro,
					site.score));
		}
		return gson.toJson(sitePOList.get(0));
	}

	/**
	 * get sites by the city name. if the result is empty, return "[]" to
	 * represent an empty set.
	 * 
	 * @param cityName
	 * @return
	 */
	public String searchSiteByCityName(String cityName) {
		int cid = service.queryInteger("getCityIdByName", cityName);
		if (cid == -1) {
			return "[]";
		}
		String result = service.query("getSitesByCityId", cid + "");

		JsonParser parser = new JsonParser();
		Gson gson = new Gson();
		JsonArray array = parser.parse(result).getAsJsonArray();
		ArrayList<SitePO> siteList = new ArrayList<SitePO>();
		for (JsonElement ele : array) {
			DbSite site = gson.fromJson(ele, DbSite.class);
			siteList.add(new SitePO(site.sname, cityName, site.intro,
					site.score));
		}
		return gson.toJson(siteList);
	}

	/**
	 * get site name list by the given rank.
	 * 
	 * @param rank
	 * @return
	 */
	public String getSiteNameListByRank(int rank) {
		ArrayList<String> siteNameList = service.queryStringList(true,
				"getSiteNameListByRank", rank + "");
		return new Gson().toJson(siteNameList);
	}

	/**
	 * check whether the given city name is in database. if exist, return true,
	 * false otherwise
	 * 
	 * @param cityName
	 * @return
	 */
	public boolean isCityNameLegal(String cityName) {
		int cid = service.queryInteger("getCityIdByName", cityName);
		return cid == -1 ? false : true;
	}

	/**
	 * get food list by the city name.
	 * 
	 * @param cityName
	 * @return a json format string ,represent a list of FoodPO
	 */
	public String getFoodListByCityName(String cityName) {
		int cid = service.queryInteger("getCityIdByName", cityName);
		if (cid == -1) {
			return "[]";
		}
		String result = service.query("getFoodListByCityId", cid + "");
		ArrayList<DbFood> foodList = JsonHelper.parseList(result, DbFood.class);
		ArrayList<FoodPO> foodPOList = new ArrayList<FoodPO>();
		for (DbFood food : foodList) {
			FoodPO foodPO = new FoodPO(food.fname, cityName, food.intro);
			foodPOList.add(foodPO);
		}
		return JsonHelper.toJson(foodPOList);
	}

	/**
	 * get the score list of each site in the city
	 * 
	 * @param city
	 * @return
	 */
	public String getScore(String cname) {
		int cid = service.queryInteger("getCityIdByName", cname);
		String result = service.query("getSiteScoreByCityId", cid + "");

		JsonParser parser = new JsonParser();
		JsonArray array = parser.parse(result).getAsJsonArray();
		Gson gson = new Gson();
		ArrayList<String> siteNameList = new ArrayList<String>();
		ArrayList<Integer> scoreList = new ArrayList<Integer>();

		for (JsonElement ele : array) {
			DbScore score = gson.fromJson(ele, DbScore.class);
			siteNameList.add(score.sname);
			scoreList.add((int) Math.floor(score.score));
		}
		return gson.toJson(new Score(siteNameList, scoreList));
	}

	/**
	 * update the score attribute
	 * 
	 * @param cname
	 *            city name
	 * @param sname
	 *            site name
	 * @param score
	 *            the new add score
	 * @return
	 */
	public boolean updateScore(String cname, String sname, int score) {
		String siteInfo = service.query("getSiteScoreByName", sname);
		// it is a list, assert its size = 1
		Gson gson = new Gson();
		JsonParser parser = new JsonParser();
		JsonArray array = parser.parse(siteInfo).getAsJsonArray();
		if (array.size() != 1) {
			return false;
		}
		DbScore dbScore = gson.fromJson(array.get(0), DbScore.class);
		double newScore = (dbScore.score * dbScore.evanum + score)
				/ (dbScore.evanum + 1);
		// update score
		HashMap<String, String> map = new HashMap<String, String>();
		map.put("sname", sname);
		service.modifySite("score", newScore + "", map);
		// update evanum
		service.modifySite("evanum", dbScore.evanum + 1 + "", map);
		return true;
	}

	public byte[] downloadImage(String cname, String sname) {
		return downloadSiteImage(cname, sname);
	}

	/**
	 * download the site image
	 * 
	 * @param cname
	 *            cityName
	 * @param sname
	 *            siteName
	 * @return a byte array
	 */
	public byte[] downloadSiteImage(String cname, String sname) {
		return service.downloadSiteImage(cname + "/" + sname + ".jpg", "JPG");
	}

	/**
	 * download the food image.
	 * 
	 * @param cname
	 *            cityName
	 * @param fname
	 *            foodName
	 * @return
	 */
	public byte[] downloadFoodImage(String cname, String fname) {
		return service.downloadFoodImage(cname + "/" + fname + ".jpg", "JPG");
	}

	/*
	 * ========================================================================
	 * Here follows methods for the site-get project to add site data to
	 * database.
	 * ========================================================================
	 */
	/**
	 * write a new city data to the city table
	 * 
	 * @param jsonStr
	 * @return
	 */
	public boolean addCity(String jsonStr) {
		Gson gson = new Gson();
		City city = gson.fromJson(jsonStr, City.class);
		DbCity dbCity = new DbCity(city.getCityName(), city.getIntroduction());
		return service.addCity(dbCity);
	}

	/**
	 * write a new site data to the site table
	 * 
	 * @param jsonStr
	 * @return
	 */
	public boolean addSite(String jsonStr) {
		Gson gson = new Gson();
		Site site = gson.fromJson(jsonStr, Site.class);
		int cid = service.queryInteger("getCityIdByName", site.getCityName());
		DbSite dbSite = new DbSite(site.getSiteName(), cid, site.getIntro(),
				site.getAddress(), site.getPhone());
		return service.addSite(dbSite);
	}

	/**
	 * write a new food data to the food table
	 * 
	 * @param jsonStr
	 * @return
	 */
	public boolean addFood(String jsonStr) {
		Gson gson = new Gson();
		Food food = gson.fromJson(jsonStr, Food.class);
		int cid = service.queryInteger("getCityIdByName", food.getCityName());
		DbFood dbFood = new DbFood(food.getFoodName(), food.getIntroduction(),
				cid);
		return service.addFood(dbFood);
	}

	/**
	 * upload site image to the specified directory
	 * 
	 * @param imageData
	 * @param cityName
	 * @param siteName
	 * @return
	 */
	public boolean uploadSiteImage(byte[] imageData, String cityName,
			String siteName) {
		return service.uploadSiteImage(imageData, cityName, siteName);
	}

	/**
	 * upload food image to the specified directory
	 * 
	 * @param imageData
	 * @param cityName
	 * @param foodName
	 * @return
	 */
	public boolean uploadFoodImage(byte[] imageData, String cityName,
			String foodName) {
		return service.uploadFoodImage(imageData, cityName, foodName);
	}
}
